import * as ww from '@wecom/jssdk'
import { getQwConfig } from '@/api/config'
import config from '@/config/index'

/**
 * 企业微信SDK包装类
 */
class QWSDK {
    constructor() {
        this.state = 'uninitialized'
        this.logger = null
        this.initialized = false
        this.configCache = {
            data: null,
            timestamp: 0,
        }
        // 配置缓存有效期（毫秒）
        this.CACHE_EXPIRATION = 7000 * 1000 // 默认7000秒，企业微信jsapi_ticket有效期为7200秒
    }

    /**
     * 设置日志记录器
     * @param logger 日志记录函数
     */
    setLogger(logger) {
        this.logger = logger
    }

    /**
     * 记录日志
     * @param message 日志消息
     */
    log(message) {
        if (this.logger) {
            this.logger(message)
        } else {
            console.log(`[QWSDK] ${message}`)
        }
    }

    /**
     * 获取企业微信配置，优先使用缓存
     * @returns 企业微信配置
     */
    async getConfig() {
        const now = Date.now()

        // 如果缓存有效，直接返回缓存的数据
        if (this.configCache.data && now - this.configCache.timestamp < this.CACHE_EXPIRATION) {
            this.log('使用缓存的企业微信配置')
            return this.configCache.data
        }

        this.log('获取新的企业微信配置')
        const res = await getQwConfig()

        if (res.code === 0 || res.code === 200) {
            const configData = res.data

            // 更新缓存
            this.configCache = {
                data: configData,
                timestamp: now,
            }

            return configData
        } else {
            throw new Error('获取企业微信配置失败: ' + res.message)
        }
    }

    /**
     * 使用Web Crypto API计算SHA-1哈希
     * @param message 需要计算哈希的消息
     * @returns SHA-1哈希值
     */
    async sha1(message) {
        const msgUint8 = new TextEncoder().encode(message)
        const hashBuffer = await crypto.subtle.digest('SHA-1', msgUint8)
        const hashArray = Array.from(new Uint8Array(hashBuffer))
        const hashHex = hashArray.map((b) => b.toString(16).padStart(2, '0')).join('')
        return hashHex
    }

    /**
     * 获取企业微信JS-SDK配置签名
     * @param url 当前网页URL
     * @param ticket JS API票据
     * @returns 签名信息
     */
    async getConfigSignature(url, jsapi_ticket) {
        this.log('获取企业微信配置签名参数: ' + url)

        const timestamp = Math.floor(Date.now() / 1000)
        const noncestr = 'noncestr_' + Math.random().toString(36).substring(2, 15)

        // 按照微信JS-SDK的规则拼接签名字符串
        const str = `jsapi_ticket=${jsapi_ticket}&noncestr=${noncestr}&timestamp=${timestamp}&url=${url}`
        this.log('签名字符串: ' + str)

        try {
            // 计算SHA-1签名
            const signature = await this.sha1(str)
            this.log('生成的签名: ' + signature)

            return {
                signature,
                nonceStr: noncestr,
                timestamp,
                url,
            }
        } catch (error) {
            this.log('签名生成失败: ' + error)
            throw error
        }
    }

    /**
     * 获取应用配置签名的适配器函数
     */
    getConfigSignatureAdapter = async (url) => {
        try {
            const config = await this.getConfig()
            const ticket = config?.jsapi_ticket || ''
            return await this.getConfigSignature(url, ticket)
        } catch (error) {
            this.log(`获取签名配置失败: ${error}`)
            throw error
        }
    }

    /**
     * 获取应用配置签名的适配器函数
     */
    getAgentConfigSignatureAdapter = async (url) => {
        try {
            const config = await this.getConfig()
            const ticket = config?.agent_jsapi_ticket || ''
            return await this.getConfigSignature(url, ticket)
        } catch (error) {
            this.log(`获取应用签名配置失败: ${error}`)
            throw error
        }
    }

    /**
     * 初始化企业微信SDK
     * @returns Promise对象
     */
    async initialize() {
        if (this.initialized) {
            this.log('企业微信SDK已经初始化，跳过')
            return
        }

        this.state = 'initializing'
        this.log('开始初始化企业微信JSSDK')

        try {
            // 获取企业微信配置（使用缓存机制）
            const qwConfig = await this.getConfig()

            // 注册企业微信SDK
            await ww.register({
                corpId: qwConfig.corp_id || config.corpId,
                agentId: qwConfig.agent_id || 0,
                jsApiList: [
                    'getCurExternalContact',
                    'openUserProfile',
                    'shareToExternalChat',
                    'sendChatMessage',
                ],
                getConfigSignature: this.getConfigSignatureAdapter,
                getAgentConfigSignature: this.getAgentConfigSignatureAdapter,
                onConfigSuccess: (res) => {
                    this.log('企微配置成功: ' + JSON.stringify(res))
                },
                onConfigFail: (res) => {
                    this.log('企微配置失败: ' + JSON.stringify(res))
                    this.state = 'failed'
                },
                onAgentConfigSuccess: (res) => {
                    this.log('企微应用配置成功: ' + JSON.stringify(res))
                    this.state = 'ready'
                },
                onAgentConfigFail: (res) => {
                    this.log('企微应用配置失败: ' + JSON.stringify(res))
                    this.state = 'failed'
                },
            })

            this.initialized = true
            this.log('企业微信JSSDK初始化成功')
        } catch (error) {
            this.state = 'failed'
            this.log('企业微信JSSDK初始化失败: ' + error)
            throw error
        }
    }

    /**
     * 获取当前外部联系人
     * @returns 外部联系人信息
     */
    async getCurExternalContact() {
        if (this.state === 'ready') {
            try {
                return await ww.getCurExternalContact()
            } catch (error) {
                this.log('获取外部联系人失败: ' + error)
                throw error
            }
        } else {
            this.log('企业微信SDK未准备好，等待300毫秒后重试')
            // 延迟300毫秒后重试
            return new Promise((resolve, reject) => {
                setTimeout(async () => {
                    try {
                        if (this.state === 'ready') {
                            const result = await ww.getCurExternalContact()
                            resolve(result)
                        } else {
                            reject(new Error('企业微信SDK仍未准备好'))
                        }
                    } catch (error) {
                        this.log('获取外部联系人失败: ' + error)
                        reject(error)
                    }
                }, 300)
            })
        }
    }

    /**
     * 打开用户资料页
     * @param userId 用户ID
     * @param type 类型
     */
    async openUserProfile(userId, type) {
        if (this.state !== 'ready') {
            this.log('企业微信SDK未准备好，无法打开用户资料')
            throw new Error('企业微信SDK未准备好')
        }

        try {
            return await ww.openUserProfile({ userid: userId, type })
        } catch (error) {
            this.log('打开用户资料失败: ' + error)
            throw error
        }
    }
}

// 创建单例实例
const qwsdk = new QWSDK()

export default qwsdk
